﻿using System;
using System.Collections.Generic;
using System.Text.RegularExpressions;
using DPLParser.DPLILCode;
using Irony.Parsing;

namespace DPLParser.DPLNodeParser.DPLScriptTreeNodeMappers.Implementations
{
    /// <summary>
    /// Extract a list of instructions from a PatternDeclaration..Operation node.
    /// </summary>
    public class DPLReducedInstructionsExtractor : AbstractDPLScriptItemsCollectionExtractor<DPLComparisonInstruction>
    {
        public DPLReducedInstructionsExtractor(ParseTreeNode originalNode) : base(originalNode)
        {
            
        }

        public override List<DPLComparisonInstruction> GetList()
        {
            AbstractDPLOperator CommonInstructionsOperator;
            List<DPLComparisonInstruction> returnOperations = new List<DPLComparisonInstruction>();

            // STEP 1: Analyse the DPL script operator
            ParseTreeNode dplTreeNode = OriginalTreeNode.GetNode(".DPLOperator");

            DPLOperatorExtractor anOperationExtractor = new DPLOperatorExtractor(dplTreeNode);
            CommonInstructionsOperator = anOperationExtractor.GetItem();

            // STEP2: Analyze variables and operations

            // Split the right member variable set in several unique variable definition;
            // make a unique DPLReducedInstruction for each independant variable definition
            ParseTreeNodeList rightMemberVariables = OriginalTreeNode.GetNodes(".RightOperationMember.*.VariableDefinition");
            ParseTreeNodeList rightMemberVariablesWithExposure = OriginalTreeNode.GetNodes(".RightOperationMember.*.VariableDefinitionWithExposure");

            ParseTreeNodeList leftMemberVariables = OriginalTreeNode.GetNodes(".LeftOperationMember.*.VariableDefinition");
            ParseTreeNodeList leftMemberVariablesWithExposure = OriginalTreeNode.GetNodes(".LeftOperationMember.*.VariableDefinitionWithExposure");

            ParseTreeNodeList leftMemberOperations = OriginalTreeNode.GetNodes(".LeftOperationMember.*.DirectOperatorName.");
            ParseTreeNodeList rightMemberOperations = OriginalTreeNode.GetNodes(".RightOperationMember.*.DirectOperatorName.");

            DPLFunctionCallExtractor leftFunctionCallExtractor = new DPLFunctionCallExtractor(OriginalTreeNode.GetNode(".LeftOperationMember"));
            DPLFunctionCall leftCall = leftFunctionCallExtractor.GetItem();

            DPLFunctionCallExtractor rightFunctionCallExtractor = new DPLFunctionCallExtractor(OriginalTreeNode.GetNode(".RightOperationMember"));
            DPLFunctionCall rightCall = rightFunctionCallExtractor.GetItem();

            // CASE 1: There are some variables in the right hand side of the equation
            foreach (var aRightVariableNode in rightMemberVariables)
            {
                DPLComparisonInstruction aNewInstruction = new DPLComparisonInstruction();
                aNewInstruction.DPLInstructionOperator = CommonInstructionsOperator;
                aNewInstruction.LeftCall = leftCall;
                aNewInstruction.RightCall = rightCall;

                aNewInstruction.RightVariableExposure = 1;
                aNewInstruction.RightVariableExposureIsInverse = false;

                // Test for right member exposure
                foreach (var aVariableWithExposure in rightMemberVariablesWithExposure)
                {
                    if (aVariableWithExposure.Contains(aRightVariableNode))
                    {
                        string strExposure = aVariableWithExposure.ChildNodes[1].Term.Name.Substring(1);
                        Regex directExposureRegex = new Regex("\\d");
                        Regex inverseExposureRegex = new Regex("(1//\\d)");
                        if (directExposureRegex.IsMatch(strExposure))
                        {
                            aNewInstruction.RightVariableExposure = Int32.Parse(strExposure);
                            aNewInstruction.RightVariableExposureIsInverse = false;
                        }
                        else
                        {
                            string strExposureExtract = aVariableWithExposure.GetNode(".OperandDigit.").Term.Name;
                            aNewInstruction.RightVariableExposure = Int32.Parse(strExposureExtract);
                            aNewInstruction.RightVariableExposureIsInverse = true;
                        }
                    }
                }

                if (leftMemberVariables.Count > 0)
                {
                    DPLVariableExtractor leftVariableExtractor = new DPLVariableExtractor(leftMemberVariables[0]);
                    aNewInstruction.LeftVariable = leftVariableExtractor.GetItem();
                }
                DPLVariableExtractor rightVariableExtractor = new DPLVariableExtractor(aRightVariableNode);
                aNewInstruction.RightVariable = rightVariableExtractor.GetItem();
                returnOperations.Add(aNewInstruction);
            }

            // CASE2: There aren't any variables in the right hand side of the equation

            return returnOperations;
        }
    }
}
